package com.evil.application.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteDepartmentService;
import com.evil.account.api.RemoteUserDepartmentService;
import com.evil.account.api.RemoteUserEnterpriseService;
import com.evil.application.api.RemoteApplicationFormControlService;
import com.evil.application.command.scope.ControlSelScopeCommand;
import com.evil.application.constant.ApplicationConstant;
import com.evil.application.convert.DataConvert;
import com.evil.application.enums.form.control.ControlCodeEnum;
import com.evil.application.enums.order.OrderSpecialControlEnum;
import com.evil.application.mapper.ApplicationFormControlMapper;
import com.evil.application.mapper.ApplicationFormMapper;
import com.evil.application.mapper.ApplicationInfoMapper;
import com.evil.application.mapper.FormControlOptionMapper;
import com.evil.application.pojo.bo.application.form.control.FormControlBO;
import com.evil.application.pojo.bo.application.form.control.option.FormControlOptionBO;
import com.evil.application.pojo.dto.form.*;
import com.evil.application.pojo.dto.form.control.*;
import com.evil.application.pojo.dto.form.control.code.*;
import com.evil.application.pojo.dto.form.control.code.config.ControlRelatedConfigDTO;
import com.evil.application.pojo.dto.form.control.code.config.ControlSelectConfigDTO;
import com.evil.application.pojo.dto.form.control.code.config.TabsConfigDTO;
import com.evil.application.pojo.dto.form.control.related.ControlRelatedDTO;
import com.evil.application.pojo.dto.form.control.save.CopyControlDTO;
import com.evil.application.pojo.dto.form.control.save.SaveControlDTO;
import com.evil.application.pojo.dto.form.control.save.SaveControlRespDTO;
import com.evil.application.pojo.dto.template.print.PrintTemplateConfigRespDTO;
import com.evil.application.pojo.dto.template.print.QueryPrintTemplateConfigReqDTO;
import com.evil.application.pojo.entity.ApplicationForm;
import com.evil.application.pojo.entity.ApplicationFormControl;
import com.evil.application.pojo.entity.ApplicationInfo;
import com.evil.application.pojo.entity.FormControlOption;
import com.evil.application.service.*;
import com.evil.application.util.ApplicationUtil;
import com.evil.application.util.ReTriggerUtil;
import com.evil.common.account.dto.department.DepartmentBaseRespDTO;
import com.evil.common.account.dto.department.DepartmentBaseTreeRespDTO;
import com.evil.common.account.dto.department.DepartmentBasesReqDTO;
import com.evil.common.account.dto.department.DepartmentTreeReqDTO;
import com.evil.common.account.dto.user.FindUserIdsByIdReqDTO;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.application.constant.ApplicationRedisConstant;
import com.evil.common.application.dto.ApplicationKeyVersionReqDTO;
import com.evil.common.application.dto.form.SpecialControlConfigDTO;
import com.evil.common.application.dto.form.control.ControlBaseDTO;
import com.evil.common.application.dto.judge.CopyJudgeReqDTO;
import com.evil.common.application.dto.judge.JudgeOr;
import com.evil.common.application.dto.judge.JudgesDTO;
import com.evil.common.application.dto.permission.app.AppPermissionDTO;
import com.evil.common.application.dto.permission.app.AppPermissionSourceDTO;
import com.evil.common.application.dto.permission.app.AppPermissionsReqDTO;
import com.evil.common.application.dto.permission.app.ModifyAppPermissionReqDTO;
import com.evil.common.application.enums.ApplicationSourceTypeEnum;
import com.evil.common.application.enums.ApplicationVersionEnum;
import com.evil.common.application.enums.PublishStatusEnum;
import com.evil.common.application.enums.form.DefaultValueTypeEnum;
import com.evil.common.application.enums.judge.JudgeSourceTypeEnum;
import com.evil.common.application.enums.permission.ApplicationPermissionTypeEnum;
import com.evil.common.application.enums.permission.PermissionStatusEnum;
import com.evil.common.application.util.ApplicationRedisKeyUtil;
import com.evil.common.core.enums.BaseEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.family.dto.FindByIdsReqDTO;
import com.evil.common.family.enums.RCodeEnum;
import com.evil.common.family.enums.SpecialFieldEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.redis.util.CacheUtil;
import com.evil.common.redis.util.RedisUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 应用表单控件表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class ApplicationFormControlServiceImpl extends ServiceImpl<ApplicationFormControlMapper, ApplicationFormControl>
        implements ApplicationFormControlService, RemoteApplicationFormControlService {

    private final LoginUtil loginUtil;

    private final RedisUtil redisUtil;

    private final CacheUtil cacheUtil;

    private final ApplicationInfoMapper applicationInfoMapper;

    private final ApplicationFormMapper applicationFormMapper;

    private final FormControlOptionMapper formControlOptionMapper;

    private final FormControlOptionService formControlOptionService;

    private final ApplicationPermissionService applicationPermissionService;

    private final ApplicationJudgeService applicationJudgeService;

    private final ApplicationFormControlRelatedService applicationFormControlRelatedService;

    private final RemoteUserEnterpriseService remoteUserEnterpriseService;

    private final RemoteUserDepartmentService remoteUserDepartmentService;

    private final RemoteDepartmentService remoteDepartmentService;

    private final ApplicationLogServiceImpl logService;

    /**
     * 应用表单控件信息
     *
     * @param applicationFormControlInfoReqTO applicationFormControlInfoReqTO
     */
    @Override
    public ApplicationFormControlRespDTO applicationFormControlInfo(ApplicationFormControlInfoReqTO applicationFormControlInfoReqTO) {
        String applicationKey = applicationFormControlInfoReqTO.getApplicationKey();
        Integer applicationVersion = applicationFormControlInfoReqTO.getApplicationVersion();
        Boolean supplySpecialControl = applicationFormControlInfoReqTO.getSupplySpecialControl();

        // 获取版本
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.findById(applicationVersion);

        // 应用信息
        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(applicationKey);
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        ApplicationForm form = applicationFormMapper.findByAppIdAndVersion(applicationInfo.getApplicationId(), versionEnum.getId());

        List<ControlDTO> controls = this.findDTOByForm(form, supplySpecialControl);

        // 表单控件层级分类
        controls = ApplicationUtil.classifyControl(controls);

        ApplicationFormControlRespDTO applicationFormControlRespDTO = new ApplicationFormControlRespDTO();
        applicationFormControlRespDTO.setApplicationKey(applicationKey);
        applicationFormControlRespDTO.setFormId(form.getFormId());
        applicationFormControlRespDTO.setControlsData(controls);
        applicationFormControlRespDTO.setPublishStatus(applicationInfo.getPublishStatus());
        return applicationFormControlRespDTO;
    }

    /**
     * 应用表单控件基础信息
     *
     * @param applicationFormControlInfoReqTO applicationFormControlInfoReqTO
     */
    @Override
    public ApplicationFormControlBaseRespDTO applicationFormControlBasesInfo(ApplicationFormControlInfoReqTO applicationFormControlInfoReqTO) {
        String applicationKey = applicationFormControlInfoReqTO.getApplicationKey();
        Integer applicationVersion = applicationFormControlInfoReqTO.getApplicationVersion();
        Boolean supplySpecialControl = applicationFormControlInfoReqTO.getSupplySpecialControl();

        // 获取版本
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.findById(applicationVersion);

        // 应用信息
        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(applicationKey);
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        ApplicationForm form = applicationFormMapper.findByAppIdAndVersion(applicationInfo.getApplicationId(), versionEnum.getId());
        List<ControlBaseDTO> controlBase = this.findBaseByForm(form, supplySpecialControl);

        ApplicationFormControlBaseRespDTO baseRespDTO = new ApplicationFormControlBaseRespDTO();
        baseRespDTO.setApplicationKey(applicationKey);
        baseRespDTO.setFormId(form.getFormId());
        baseRespDTO.setControlBases(controlBase);
        return baseRespDTO;
    }

    /**
     * 应用表单控件基础信息列表
     *
     * @param applicationKeyVersionReqDTO applicationKeyVersionReqDTO
     */
    @Override
    public List<ControlBaseInfoDTO> controlBases(ApplicationKeyVersionReqDTO applicationKeyVersionReqDTO) {
        String applicationKey = applicationKeyVersionReqDTO.getApplicationKey();
        Integer applicationVersion = applicationKeyVersionReqDTO.getApplicationVersion();

        // 获取版本
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.findById(applicationVersion);
        // 应用信息
        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(applicationKey);
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());
        ApplicationForm form = applicationFormMapper.findByAppIdAndVersion(applicationInfo.getApplicationId(), versionEnum.getId());
        return this.findBaseInfoByForm(form, false);
    }

    /**
     * 应用表单控件基础信息列表（高级筛选版）
     *
     * @param formControlListReqDTO formControlListReqDTO
     */
    @Override
    public List<ControlBaseInfoDTO> applicationFormControlList(FormControlListReqDTO formControlListReqDTO) {
        String applicationKey = formControlListReqDTO.getApplicationKey();
        Integer applicationVersion = formControlListReqDTO.getApplicationVersion();
        String controlCode = formControlListReqDTO.getControlCode();
        Boolean similar = formControlListReqDTO.getSimilar();
        Boolean supplySpecialControl = formControlListReqDTO.getSupplySpecialControl();

        // 获取版本
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.findById(applicationVersion);

        // 应用信息
        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(applicationKey);
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        List<ControlBaseInfoDTO> controlBases = this.findBaseInfoByAppId(applicationInfo.getApplicationId(), versionEnum, supplySpecialControl);
        Predicate<ControlBaseInfoDTO> filter;
        if (similar) {
            // 过滤 同类型分类
            String type = StringUtils.isNotBlank(controlCode) ? ControlCodeEnum.findByCode(controlCode).getType().getType() : null;
            filter = e -> ControlCodeEnum.findByCode(e.getControlCode()).getType().isCompatible(type);
        } else {
            // 过滤 同类型
            filter = e -> StringUtils.isBlank(controlCode) || controlCode.equals(e.getControlCode());
        }
        return StreamUtil.filter(controlBases, filter);
    }

    /**
     * 编辑应用表单控件
     *
     * @param modifyApplicationFormControlReqDTO modifyApplicationFormRespDTO
     */
    @Override
    public synchronized void modifyApplicationFormControl(ModifyApplicationFormControlReqDTO modifyApplicationFormControlReqDTO) {
        // 检查是否是管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        String applicationKey = modifyApplicationFormControlReqDTO.getApplicationKey();
        Long formId = modifyApplicationFormControlReqDTO.getFormId();

        ApplicationForm form = applicationFormMapper.findById(formId);
        // 不允许编辑发布版
        if (ApplicationVersionEnum.RELEASE_VERSION.getId() == form.getApplicationVersion()) {
            throw new BusinessException(BaseEnum.ACCESS_DENIED);
        }

        ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(applicationKey);
        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        // 检查控件
        this.checkFormControl(modifyApplicationFormControlReqDTO.getControlList());

        cacheUtil.clearRequestCache(() -> {
            // 表单控件
            this.modifyControls(form, modifyApplicationFormControlReqDTO.getControlList());

            // 记录 清理应用表单缓存
            cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.applicationFormKey(applicationInfo.getApplicationId(), form.getApplicationVersion()));

            // 有未部署
            applicationInfo.setPublishStatus(PublishStatusEnum.UN_PUBLISH.getId());
            logService.saveAndCheck(applicationInfoMapper, ApplicationInfo::getApplicationId, applicationInfo);
        });
    }

    /**
     * 应用表单控件条件
     *
     * @param formControlListReqDTO formControlListReqDTO
     */
    @Override
    public List<ControlConditionRespDTO> applicationFormControlCondition(FormControlListReqDTO formControlListReqDTO) {
        List<ControlBaseInfoDTO> controlBases = this.applicationFormControlList(formControlListReqDTO);

        List<ControlConditionRespDTO> conditions = new ArrayList<>();
        // 递归处理
        this.recursionControlCondition(conditions, ApplicationUtil.classifyBaseControl(controlBases));
        return conditions;
    }

    /**
     * 应用表单控件树
     *
     * @param controlTreeReqDTO controlTreeReqDTO
     * @return List
     */
    @Override
    public List<FormControlTreeRespDTO> applicationControlTree(ControlTreeReqDTO controlTreeReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(controlTreeReqDTO.getEnterpriseId());
        Integer applicationVersion = controlTreeReqDTO.getApplicationVersion();
        boolean relateControl = controlTreeReqDTO.getRelateControl();

        ApplicationVersionEnum.findById(applicationVersion);

        // 检查企业管理员
        remoteUserEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        // 优先获取缓存
        String key = ApplicationRedisKeyUtil.enterpriseAppTreeKey(enterpriseId, applicationVersion);
        List<?> list = (List<?>) redisUtil.get(key);
        if (Objects.nonNull(list)) {
            return list.stream().map(e -> (FormControlTreeRespDTO) e).collect(Collectors.toList());
        }

        Map<Long, ApplicationInfo> appMap = StreamUtil.toMapK(applicationInfoMapper.findByEnterpriseId(enterpriseId), ApplicationInfo::getApplicationId);

        // 获取应用表单列表
        List<ApplicationForm> forms = applicationFormMapper.findByAppIdsAndVersion(appMap.keySet(), applicationVersion);
        List<Long> formIds = StreamUtil.transListT(forms, ApplicationForm::getFormId);

        // 获取应用表单控件列表
        List<ApplicationFormControl> controls = this.baseMapper.findByFormIds(formIds);
        Map<Long, Long> controlFormIdMap = StreamUtil.toMapKV(controls, ApplicationFormControl::getControlId, ApplicationFormControl::getFormId);

        // 获取应用表单控件Map
        Map<Long, List<ControlBaseInfoDTO>> formControlsMap = StreamUtil.groupK(this.transBaseInfo(controls), c -> controlFormIdMap.get(c.getControlId()));

        // 表单控件树
        List<FormControlTreeRespDTO> controlTree = forms.stream().map(form -> {
            // 表单
            FormControlTreeRespDTO tree = new FormControlTreeRespDTO(form);
            if (appMap.containsKey(form.getApplicationId())) {
                tree.setApplicationKey(appMap.get(form.getApplicationId()).getApplicationKey());
            }
            if (formControlsMap.containsKey(form.getFormId())) {
                List<ControlBaseInfoDTO> controlBases = formControlsMap.get(form.getFormId());
                if (relateControl) {
                    // 补充特殊控件
                    SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(form.getSpecialControlConfig());
                    controlBases.addAll(OrderSpecialControlEnum.initControlBases(specialControlConfigDTO));
                }
                tree.setControls(ApplicationUtil.classifyBaseControl(controlBases));
            }
            return tree;
        }).collect(Collectors.toList());

        // 缓存
        redisUtil.set(key, controlTree, ApplicationRedisConstant.ENTERPRISE_APP_TREE_EXPIRE_IN_SECOND);

        return controlTree;
    }

    /**
     * 应用表单控件 可选择部门列表
     *
     * @param memberSelControlReqDTO memSelControlReqDTO
     * @return List
     */
    @Override
    public List<DepartmentBaseRespDTO> getDeptSelectList(MemberSelControlReqDTO memberSelControlReqDTO) {
        Long controlId = memberSelControlReqDTO.getControlId();
        ApplicationFormControl control = this.findById(controlId);
        ApplicationForm applicationForm = applicationFormMapper.findById(control.getFormId());
        ApplicationInfo applicationInfo = applicationInfoMapper.findById(applicationForm.getApplicationId());

        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        if (!ControlCodeEnum.DEPT_SEL.getCode().equals(control.getControlCode())) {
            return new ArrayList<>();
        }

        ControlSelectConfigDTO memberSelectConfig = JSON.parseObject(control.getControlSelectConfig(), ControlSelectConfigDTO.class);
        if (PermissionStatusEnum.ALL.getId() == memberSelectConfig.getPermissionStatus()) {
            // 非配置时查询 并且 控件权限类型为全体
            return remoteDepartmentService.bases(new DepartmentBasesReqDTO(applicationInfo.getEnterpriseId()));
        } else {
            // 配置时查询 或者 控件权限类型为指定
            AppPermissionSourceDTO appPermissionReqDTO = new AppPermissionSourceDTO(ApplicationSourceTypeEnum.FORM_CONTROL_DEPT_SELECT_SCOPE, controlId);
            List<Long> departmentIds = applicationPermissionService.findDTOBySource(appPermissionReqDTO).stream()
                    .filter(e -> ApplicationPermissionTypeEnum.DEPARTMENT.getId() == e.getPermissionType())
                    .map(AppPermissionDTO::getTargetId)
                    .collect(Collectors.toList());
            return remoteDepartmentService.findBaseByIds(FindByIdsReqDTO.filter(departmentIds));
        }
    }

    /**
     * 应用表单控件 可选择部门列表
     *
     * @param memberSelControlReqDTO memSelControlReqDTO
     * @return List
     */
    @Override
    public List<DepartmentBaseTreeRespDTO> getDeptSelectTree(MemberSelControlReqDTO memberSelControlReqDTO) {
        Long controlId = memberSelControlReqDTO.getControlId();
        ApplicationFormControl control = this.findById(controlId);
        ApplicationForm applicationForm = applicationFormMapper.findById(control.getFormId());
        ApplicationInfo applicationInfo = applicationInfoMapper.findById(applicationForm.getApplicationId());

        // 检查企业
        loginUtil.checkEnterpriseId(applicationInfo.getEnterpriseId());

        if (!ControlCodeEnum.DEPT_SEL.getCode().equals(control.getControlCode())) {
            return new ArrayList<>();
        }

        ControlSelectConfigDTO memberSelectConfig = JSON.parseObject(control.getControlSelectConfig(), ControlSelectConfigDTO.class);
        if (PermissionStatusEnum.ALL.getId() == memberSelectConfig.getPermissionStatus()) {
            // 非配置时查询 并且 控件权限类型为全体
            return remoteDepartmentService.baseTree(DepartmentTreeReqDTO.filter(applicationInfo.getEnterpriseId()));
        } else {
            // 配置时查询 或者 控件权限类型为指定
            AppPermissionSourceDTO appPermissionReqDTO = new AppPermissionSourceDTO(ApplicationSourceTypeEnum.FORM_CONTROL_DEPT_SELECT_SCOPE, controlId);
            List<Long> departmentIds = applicationPermissionService.findDTOBySource(appPermissionReqDTO).stream()
                    .filter(e -> ApplicationPermissionTypeEnum.DEPARTMENT.getId() == e.getPermissionType())
                    .map(AppPermissionDTO::getTargetId)
                    .collect(Collectors.toList());
            return remoteDepartmentService.baseTree(DepartmentTreeReqDTO.filter(applicationInfo.getEnterpriseId(), departmentIds));
        }
    }

    /**
     * 应用表单控件 可选择成员列表
     *
     * @param memberSelControlReqDTO memSelControlReqDTO
     * @return List
     */
    @Override
    public List<UserBaseRespDTO> getUserSelectList(MemberSelControlReqDTO memberSelControlReqDTO) {
        String applicationKey = memberSelControlReqDTO.getApplicationKey();
        Long controlId = memberSelControlReqDTO.getControlId();

        Long enterpriseId;
        String controlCode;
        Integer permissionStatus;
        Optional<OrderSpecialControlEnum> specialControlEnumOptional = OrderSpecialControlEnum.isExistById(controlId);
        if (specialControlEnumOptional.isPresent()) {
            // 特殊控件
            if (StringUtils.isBlank(applicationKey)) {
                throw new BusinessException(RCodeEnum.ERROR_PARAMETER, "应用key不能为空");
            }
            ApplicationInfo applicationInfo = applicationInfoMapper.findByKey(applicationKey);

            controlCode = specialControlEnumOptional.get().getControlCode().getCode();
            permissionStatus = PermissionStatusEnum.ALL.getId();
            enterpriseId = applicationInfo.getEnterpriseId();
        } else {
            // 表单控件
            ApplicationFormControl control = this.baseMapper.findById(controlId);
            ApplicationForm applicationForm = applicationFormMapper.findById(control.getFormId());
            ApplicationInfo applicationInfo = applicationInfoMapper.findById(applicationForm.getApplicationId());
            ControlSelectConfigDTO memberSelectConfig = JSON.parseObject(control.getControlSelectConfig(), ControlSelectConfigDTO.class);

            controlCode = control.getControlCode();
            permissionStatus = memberSelectConfig.getPermissionStatus();
            enterpriseId = applicationInfo.getEnterpriseId();
        }

        // 检查企业
        loginUtil.checkEnterpriseId(enterpriseId);
        // 检查控件类型
        if (!ControlCodeEnum.MEMBER_SEL.getCode().equals(controlCode)) {
            return new ArrayList<>();
        }
        // 权限类型
        if (PermissionStatusEnum.ALL.getId() == permissionStatus) {
            // 非配置时查询 并且 控件权限类型为全体
            return remoteUserEnterpriseService.enterpriseUserBases(FindUserIdsByIdReqDTO.filter(enterpriseId));
        } else {
            // 配置时查询 或者 控件权限类型为指定
            AppPermissionSourceDTO appPermissionReqDTO = new AppPermissionSourceDTO(ApplicationSourceTypeEnum.FORM_CONTROL_MEMBER_SELECT_SCOPE, controlId);
            return applicationPermissionService.getPermissionUsersBySource(appPermissionReqDTO, true);
        }
    }

    /**
     * 查看模板配置对照表
     *
     * @param queryPrintTemplateConfigReqDTO queryTemplateConfigReqDTO
     * @return List
     */
    @Override
    public List<PrintTemplateConfigRespDTO> queryPrintTemplateConfig(QueryPrintTemplateConfigReqDTO queryPrintTemplateConfigReqDTO) {
        List<Long> controlIds = queryPrintTemplateConfigReqDTO.getControlIds();
        ApplicationInfo app = applicationInfoMapper.findByKey(queryPrintTemplateConfigReqDTO.getApplicationKey());
        ApplicationVersionEnum versionEnum = ApplicationVersionEnum.findById(queryPrintTemplateConfigReqDTO.getVersion());
        List<ControlBaseDTO> controlBases = this.findBaseByApp(app, versionEnum, queryPrintTemplateConfigReqDTO.getIsSpecial());
        return ApplicationUtil.buildControlTemplateConfig(controlBases, controlIds);
    }

    // region query ApplicationFormControl

    /**
     * 获取应用表单控件
     *
     * @param id id
     * @return ApplicationFormControl
     */
    @Override
    public ApplicationFormControl findById(Long id) {
        return this.baseMapper.findById(id);
    }

    /**
     * 获取应用表单控件列表
     *
     * @param ids           ids
     * @param filterDeleted filterDeleted
     * @return ApplicationFormControl列表
     */
    @Override
    public List<ApplicationFormControl> findByControlIds(Collection<Long> ids, boolean filterDeleted) {
        return this.baseMapper.findByIds(ids, filterDeleted);
    }

    /**
     * 获取应用表单控件列表
     *
     * @param formId               formId
     * @param supplySpecialControl 是否补充特殊控件
     * @return ApplicationFormControl列表
     */
    @Override
    public List<ApplicationFormControl> findByFormId(Long formId, boolean supplySpecialControl) {
        ApplicationForm form = applicationFormMapper.findById(formId);
        return this.findByForm(form, supplySpecialControl);
    }

    /**
     * 获取应用表单控件列表
     *
     * @param applicationForm      applicationForm
     * @param supplySpecialControl 是否补充特殊控件
     * @return ApplicationFormControl列表
     */
    @Override
    public List<ApplicationFormControl> findByForm(ApplicationForm applicationForm, boolean supplySpecialControl) {
        List<ApplicationFormControl> controls = this.baseMapper.findByFormId(applicationForm.getFormId());
        SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(applicationForm.getSpecialControlConfig());
        return ApplicationUtil.supplySpecialControls(specialControlConfigDTO, controls, supplySpecialControl);
    }

    @Override
    public List<ApplicationFormControl> findByFormAndControlCode(ApplicationForm applicationForm, String controlCode) {
        return this.baseMapper.findByFormIdAndControlCode(applicationForm.getFormId(), controlCode);
    }

    /**
     * 获取应用表单控件列表
     *
     * @param appId                appId
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ApplicationFormControl列表
     */
    @Override
    public List<ApplicationFormControl> findByAppId(Long appId, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        ApplicationForm form = applicationFormMapper.findByAppIdAndVersion(appId, versionEnum.getId());
        return this.findByForm(form, supplySpecialControl);
    }

    /**
     * 获取应用表单控件列表
     *
     * @param applicationInfo      applicationInfo
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ApplicationFormControl列表
     */
    @Override
    public List<ApplicationFormControl> findByApp(ApplicationInfo applicationInfo, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        return this.findByAppId(applicationInfo.getApplicationId(), versionEnum, supplySpecialControl);
    }
    // endregion

    // region query ControlDTO

    /**
     * 获取应用表单控件实体
     *
     * @param id          id
     * @param dataConvert 为null将不会初始化
     * @return ControlDTO
     */
    @Override
    public ControlDTO findDTOByControlId(Long id, DataConvert dataConvert) {
        ApplicationFormControl control = this.baseMapper.findById(id);
        return StreamUtil.findFirst(ApplicationUtil.controlsToDTO(Collections.singletonList(control), dataConvert));
    }

    /**
     * 获取应用表单控件实体列表
     *
     * @param ids           ids
     * @param filterDeleted filterDeleted
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> findDTOByControlIds(Collection<Long> ids, boolean filterDeleted) {
        return this.transDTO(this.findByControlIds(ids, filterDeleted));
    }

    /**
     * 获取应用表单控件实体列表
     *
     * @param ids           ids
     * @param filterDeleted filterDeleted
     * @return ControlDTO列表
     */
    @Override
    public Map<Long, ControlDTO> findDTOMapByControlIds(Collection<Long> ids, boolean filterDeleted) {
        return StreamUtil.toMapK(this.findDTOByControlIds(ids, filterDeleted), ControlDTO::getControlId);
    }

    /**
     * 转换DTO
     *
     * @param controls controls
     * @return ControlDTO 列表
     */
    @Override
    public List<ControlDTO> transDTO(Collection<ApplicationFormControl> controls) {
        DataConvert dataConvert = new DataConvert(loginUtil)
                .initFormMap()
                .initControlMap()
                .initControlRelatedBasesMap()
                .initOptionMap()
                .initPermissionMap()
                .initJudgeMap();

        return ApplicationUtil.controlsToDTO(controls, dataConvert);
    }

    /**
     * 获取应用表单控件实体列表
     *
     * @param formId               formId
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> findDTOByFormId(Long formId, boolean supplySpecialControl) {
        ApplicationForm form = applicationFormMapper.findById(formId);
        return this.findDTOByForm(form, supplySpecialControl);
    }

    /**
     * 获取应用表单控件实体列表
     *
     * @param applicationForm      applicationForm
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> findDTOByForm(ApplicationForm applicationForm, boolean supplySpecialControl) {
        return this.transDTO(this.findByForm(applicationForm, supplySpecialControl));
    }

    /**
     * 获取应用表单控件实体列表
     *
     * @param appId                appId
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> findDTOByAppId(Long appId, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        return this.transDTO(this.findByAppId(appId, versionEnum, supplySpecialControl));
    }

    /**
     * 获取应用表单控件实体列表
     *
     * @param applicationInfo      applicationInfo
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> findDTOByApp(ApplicationInfo applicationInfo, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        return this.findDTOByAppId(applicationInfo.getApplicationId(), versionEnum, supplySpecialControl);
    }

    /**
     * 获取发布版 控件实体列表（缓存版）
     *
     * @param appId appId
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> appReleaseControlDTOs_Cache(Long appId) {
        ApplicationInfo applicationInfo = applicationInfoMapper.findById(appId);
        return this.appReleaseControlDTOs_Cache(applicationInfo);
    }

    /**
     * 获取发布版 控件实体列表（缓存版）
     *
     * @param applicationInfo applicationInfo
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> appReleaseControlDTOs_Cache(ApplicationInfo applicationInfo) {
        String key = ApplicationRedisKeyUtil.enterpriseAppControlsKey(applicationInfo.getEnterpriseId(),
                applicationInfo.getApplicationId(), ApplicationVersionEnum.RELEASE_VERSION.getId());
        List<?> list = (List<?>) redisUtil.get(key);
        if (Objects.nonNull(list)) {
            return list.stream().map(e -> (ControlDTO) e).collect(Collectors.toList());
        } else {
            List<ControlDTO> controls = this.appReleaseControlDTOs(applicationInfo.getApplicationId(), true);
            redisUtil.set(key, controls, ApplicationRedisConstant.ENTERPRISE_APP_CONTROL_KEY_EXPIRE_IN_SECOND);
            return controls;
        }
    }

    /**
     * 获取发布版 控件实体列表（缓存版）
     *
     * @param applicationInfo applicationInfo
     * @return ControlDTO列表
     */
    @Override
    public Map<Long, ControlDTO> appReleaseControlDTOMap_Cache(ApplicationInfo applicationInfo) {
        return StreamUtil.toMapK(this.appReleaseControlDTOs_Cache(applicationInfo), ControlDTO::getControlId);
    }

    /**
     * 发布版应用表单控件实体列表
     *
     * @param appId                appId
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlDTO列表
     */
    @Override
    public List<ControlDTO> appReleaseControlDTOs(Long appId, boolean supplySpecialControl) {
        return this.findDTOByAppId(appId, ApplicationVersionEnum.RELEASE_VERSION, supplySpecialControl);
    }
    // endregion

    // region query ControlBaseDTO

    /**
     * 获取控件基础信息
     *
     * @param controlId controlId
     * @return ControlBaseDTO
     */
    @Override
    public ControlBaseDTO findBaseById(Long controlId) {
        return this.baseMapper.findBaseById(controlId);
    }

    /**
     * 获取控件基础信息列表
     *
     * @param controlIds controlIds
     * @return ControlBaseDTO
     */
    @Override
    public List<ControlBaseDTO> findBaseByIds(Collection<Long> controlIds) {
        return this.baseMapper.findBaseByIds(controlIds, true);
    }

    /**
     * 获取控件基础信息列表
     *
     * @param controlIds controlIds
     * @return ControlBaseDTO
     */
    @Override
    public Map<Long, ControlBaseDTO> findBaseMapByIds(Collection<Long> controlIds) {
        return StreamUtil.toMapK(this.findBaseByIds(controlIds), ControlBaseDTO::getControlId);
    }

    /**
     * 获取控件基础信息列表
     *
     * @param formIds              formIds
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseDTO
     */
    @Override
    public List<ControlBaseDTO> findBaseByFormIds(Collection<Long> formIds, boolean supplySpecialControl) {
        List<ControlBaseDTO> controlBases = this.baseMapper.findBaseByFormIds(formIds);
        if (supplySpecialControl) {
            List<ApplicationForm> forms = applicationFormMapper.findByIds(formIds, false);
            forms.forEach(form -> {
                SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(form.getSpecialControlConfig());
                OrderSpecialControlEnum.supplySpecialControlBases(specialControlConfigDTO, controlBases, supplySpecialControl);
            });
        }
        return controlBases;
    }

    /**
     * 获取控件基础信息列表
     *
     * @param formId               formId
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseDTO
     */
    @Override
    public List<ControlBaseDTO> findBaseByFormId(Long formId, boolean supplySpecialControl) {
        ApplicationForm form = applicationFormMapper.findById(formId);
        return this.findBaseByForm(form, supplySpecialControl);
    }

    /**
     * 获取控件基础信息列表
     *
     * @param form                 form
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseDTO
     */
    @Override
    public List<ControlBaseDTO> findBaseByForm(ApplicationForm form, boolean supplySpecialControl) {
        List<ControlBaseDTO> controlBases = this.baseMapper.findBaseByFormId(form.getFormId());
        if (supplySpecialControl) {
            SpecialControlConfigDTO specialControlConfigDTO = ApplicationUtil.specialControlConfig(form.getSpecialControlConfig());
            OrderSpecialControlEnum.supplySpecialControlBases(specialControlConfigDTO, controlBases, supplySpecialControl);
        }
        return controlBases;
    }

    @Override
    public List<ControlBaseDTO> findBaseByForm(ApplicationForm form, String controlCode) {
        return this.baseMapper.findBaseByFormIdAndControlCode(form.getFormId(), controlCode);
    }

    /**
     * 获取控件基础信息列表
     *
     * @param appId                appId
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseDTO
     */
    @Override
    public List<ControlBaseDTO> findBaseByAppId(Long appId, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        ApplicationForm form = applicationFormMapper.findByAppIdAndVersion(appId, versionEnum.getId());
        return this.baseMapper.findBaseByFormId(form.getFormId());
    }

    /**
     * 获取控件基础信息列表
     *
     * @param app                  app
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseDTO
     */
    @Override
    public List<ControlBaseDTO> findReleaseBaseByApp(ApplicationInfo app, boolean supplySpecialControl) {
        return this.findBaseByApp(app, ApplicationVersionEnum.RELEASE_VERSION, supplySpecialControl);
    }

    /**
     * 获取控件基础信息列表
     *
     * @param app                  app
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseDTO
     */
    @Override
    public Map<Long, ControlBaseDTO> findReleaseBaseMapByApp(ApplicationInfo app, boolean supplySpecialControl) {
        return StreamUtil.toMapK(this.findReleaseBaseByApp(app, supplySpecialControl), ControlBaseDTO::getControlId);
    }

    /**
     * 获取控件基础信息列表
     *
     * @param app                  app
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseDTO
     */
    @Override
    public List<ControlBaseDTO> findBaseByApp(ApplicationInfo app, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        ApplicationForm form = applicationFormMapper.findByAppIdAndVersion(app.getApplicationId(), versionEnum.getId());
        return this.findBaseByForm(form, supplySpecialControl);
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param ids ids
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public Map<Long, String> controlCodeMap(Collection<Long> ids) {
        if (CollectionUtil.isEmpty(ids)) {
            return new HashMap<>();
        }
        List<ControlBaseDTO> controlBases = this.baseMapper.findBaseByIds(ids, true);
        // 特殊控件处理
        List<Long> specialControlIds = OrderSpecialControlEnum.filterSpecialControlIds(ids);
        SpecialControlConfigDTO specialControlConfigDTO = new SpecialControlConfigDTO();
        List<ControlBaseDTO> specialControlBase = StreamUtil.transListT(specialControlIds, e -> OrderSpecialControlEnum.findById(e).toControlBase(specialControlConfigDTO));
        controlBases.addAll(specialControlBase);
        // 构建返回
        return StreamUtil.toMapKV(controlBases, ControlBaseDTO::getControlId, ControlBaseDTO::getControlCode);
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param formId               formId
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public Map<Long, String> controlCodeMap(Long formId, boolean supplySpecialControl) {
        return StreamUtil.toMapKV(this.findBaseByFormId(formId, supplySpecialControl), ControlBaseDTO::getControlId, ControlBaseDTO::getControlCode);
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param formIds              formIds
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public Map<Long, String> controlCodeMap(Collection<Long> formIds, boolean supplySpecialControl) {
        List<ControlBaseDTO> controlBases = this.findBaseByFormIds(formIds, supplySpecialControl);
        return StreamUtil.toOrderlyMapKV(controlBases, ControlBaseDTO::getControlId, ControlBaseDTO::getControlCode);
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param appId                appId
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public Map<Long, String> controlCodeMap(Long appId, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        ApplicationForm form = applicationFormMapper.findByAppIdAndVersion(appId, versionEnum.getId());
        return StreamUtil.toMapKV(this.findBaseByForm(form, supplySpecialControl), ControlBaseDTO::getControlId, ControlBaseDTO::getControlCode);
    }
    // endregion

    // region query ControlBaseInfoDTO

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param ids ids
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public List<ControlBaseInfoDTO> findBaseInfoByControlIds(Collection<Long> ids) {
        return this.transBaseInfo(this.findByControlIds(ids, true));
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param ids ids
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public Map<Long, ControlBaseInfoDTO> findBaseInfoMapByControlIds(Collection<Long> ids) {
        return StreamUtil.toMapK(this.findBaseInfoByControlIds(ids), ControlBaseInfoDTO::getControlId);
    }

    /**
     * 转换Base
     *
     * @param controls controls
     * @return ControlBaseInfoDTO 列表
     */
    @Override
    public List<ControlBaseInfoDTO> transBaseInfo(Collection<ApplicationFormControl> controls) {
        DataConvert dataConvert = new DataConvert(loginUtil).initOptionMap();
        return ApplicationUtil.controlToBase(controls, dataConvert);
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param formId               formId
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public List<ControlBaseInfoDTO> findBaseInfoByFormId(Long formId, boolean supplySpecialControl) {
        return this.transBaseInfo(this.findByFormId(formId, supplySpecialControl));
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param form                 applicationForm
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public List<ControlBaseInfoDTO> findBaseInfoByForm(ApplicationForm form, boolean supplySpecialControl) {
        return this.transBaseInfo(this.findByForm(form, supplySpecialControl));
    }

    @Override
    public List<ControlBaseInfoDTO> findBaseInfoByForm(ApplicationForm form, String controlCode) {
        return this.transBaseInfo(this.findByFormAndControlCode(form, controlCode));
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param appId                appId
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public List<ControlBaseInfoDTO> findBaseInfoByAppId(Long appId, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        return this.transBaseInfo(this.findByAppId(appId, versionEnum, supplySpecialControl));
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param appId                appId
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public Map<Long, ControlBaseInfoDTO> findBaseInfoMapByAppId(Long appId, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        return StreamUtil.toMapK(this.findBaseInfoByAppId(appId, versionEnum, supplySpecialControl), ControlBaseInfoDTO::getControlId);
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param app                  app
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public List<ControlBaseInfoDTO> findReleaseBaseInfoByApp(ApplicationInfo app, boolean supplySpecialControl) {
        return this.findBaseInfoByApp(app, ApplicationVersionEnum.RELEASE_VERSION, supplySpecialControl);
    }

    /**
     * 获取应用表单控件基础信息列表
     *
     * @param app                  applicationInfo
     * @param versionEnum          versionEnum
     * @param supplySpecialControl 是否补充特殊控件
     * @return ControlBaseInfoDTO列表
     */
    @Override
    public List<ControlBaseInfoDTO> findBaseInfoByApp(ApplicationInfo app, ApplicationVersionEnum versionEnum, boolean supplySpecialControl) {
        return this.findBaseInfoByAppId(app.getApplicationId(), versionEnum, supplySpecialControl);
    }
    // endregion

    /**
     * 保存表单控件
     *
     * @param form     applicationForm
     * @param controls controls
     */
    @Override
    public void modifyControls(ApplicationForm form, List<ControlDTO> controls) {
        Map<Long, ApplicationFormControl> controlMap = StreamUtil.toMapK(this.findByForm(form, false), ApplicationFormControl::getControlId);

        List<FormControlOption> options = formControlOptionMapper.findByControlIds(controlMap.keySet(), false);
        Map<Long, Map<Long, FormControlOption>> controlOptionsMap = StreamUtil.groupAndThenTransMapK(options, FormControlOption::getControlId, FormControlOption::getOptionId);

        SaveControlRespDTO saveControl = new SaveControlRespDTO(form, controlMap, controlOptionsMap);
        // 递归保存控件
        this.recursionModifyControls(null, controls, saveControl);

        // 处理 逻辑表单
        logService.saveAndCheck(formControlOptionMapper, FormControlOption::getOptionId, saveControl.handleLinkControlOptions());

        // 删除无效控件
        List<ApplicationFormControl> deletedControls = controlMap.values().stream()
                .filter(e -> !saveControl.getControlIds().contains(e.getControlId()))
                .peek(e -> e.setIsDeleted(SwitchEnum.YES.getId()))
                .collect(Collectors.toList());
        logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, deletedControls);

        // 记录 移除表单缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.formKey(form.getFormId()));
        // 记录 移除表单控件缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.formControlsKey(form.getFormId()));
        // 记录 移除控件缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.controlsKey(saveControl.getControlIds()).values());
        // 记录 移除控件选项缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.controlOption(saveControl.getControlIds()).values());
    }

    /**
     * 复制表单控件
     *
     * @param targetApp    targetApp
     * @param source       source
     * @param target       target
     * @param updateSource 是否更新源映射
     * @return CopyControlRespDTO
     */
    @Override
    public CopyControlDTO copyControls(ApplicationInfo targetApp, ApplicationForm source, ApplicationForm target, boolean updateSource) {
        // 源控件列表
        List<ApplicationFormControl> controls = this.findByForm(source, false);
        // 源控件map（源控件id：控件）
        Map<Long, ApplicationFormControl> sourceControlMap = StreamUtil.toMapK(controls, ApplicationFormControl::getControlId);
        // 源控件树（控件树）
        List<FormControlBO> sourceControlTree = ApplicationUtil.classifyControlBO(controls);
        // 源控件选项map（源控件id：控件选项树）
        List<FormControlOption> options = formControlOptionMapper.findByControlIds(sourceControlMap.keySet(), true);
        Map<Long, List<FormControlOptionBO>> sourceControlOptionMap = options.stream()
                // 按控件分组
                .collect(Collectors.groupingBy(FormControlOption::getControlId,
                        // 实体转BO
                        Collectors.mapping(FormControlOptionBO::new,
                                // 层级分类
                                Collectors.collectingAndThen(Collectors.toList(), ApplicationUtil::classifyOptionBOs))));

        // 目标控件列表
        List<ApplicationFormControl> targetControls = this.findByForm(target, false);
        // 目标控件与源映射map（目标控件id：控件） 过滤没有源映射的控件
        Map<Long, ApplicationFormControl> targetSourceControlMap = StreamUtil.toMapFK(targetControls,
                e -> !ApplicationUtil.DEFAULT_SOURCE_CONTROL_ID.equals(e.getSourceControlId()), ApplicationFormControl::getSourceControlId);
        // 目标控件ids
        List<Long> targetControlIds = StreamUtil.transListT(targetControls, ApplicationFormControl::getControlId);
        // 目标控件选项
        List<FormControlOption> targetOptions = formControlOptionMapper.findByControlIds(targetControlIds, true);
        // 目标控件id：（目标控件sourceOptionId：目标控件选项）
        Map<Long, Map<Long, FormControlOption>> targetSourceControlOptionMap = StreamUtil.groupFAndThenTransMapK(
                targetOptions, e -> !ApplicationUtil.DEFAULT_SOURCE_OPTION_ID.equals(e.getSourceOptionId()),
                FormControlOption::getControlId, FormControlOption::getSourceOptionId);

        CopyControlDTO copyControlDTO = new CopyControlDTO(target);
        // 递归复制表单控件
        this.recursionCopyControl(targetSourceControlMap, sourceControlOptionMap, targetSourceControlOptionMap, null, sourceControlTree, copyControlDTO, updateSource);
        // 替换公式
        logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, copyControlDTO.handleReplaceFormula(ReTriggerUtil::replaceFormulaControlId));

        // 处理下拉选项
        logService.saveAndCheck(formControlOptionMapper, FormControlOption::getOptionId, copyControlDTO.handleLinkControlOptions());

        // 部门选择控件 选择范围 复制
        this.copyControlSelScore(target, controls, copyControlDTO.getControlIdMap(), false);
        // 成员选择控件 选择范围 复制
        this.copyControlSelScore(target, controls, copyControlDTO.getControlIdMap(), true);

        // 删除失效控件
        this.deleteFormControls(StreamUtil.filter(targetControls, e -> !copyControlDTO.getControlIds().contains(e.getControlId())));

        // 记录 移除企业应用树缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.enterpriseAppTreeKey(targetApp.getEnterpriseId(), target.getApplicationVersion()));
        // 记录 移除企业应用控件缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.enterpriseAppControlsKey(targetApp.getEnterpriseId(), targetApp.getApplicationId(), target.getApplicationVersion()));
        // 记录 移除应用缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.applicationIdKey(targetApp.getApplicationId()));
        // 记录 移除应用缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.applicationKey(targetApp.getApplicationKey()));
        // 记录 移除表单控件缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.formControlsKey(source.getFormId()));
        // 记录 移除表单控件缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.formControlsKey(target.getFormId()));
        // 记录 移除控件缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.controlsKey(copyControlDTO.getControlIdMap().keySet()).values());
        // 记录 移除控件缓存
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.controlsKey(copyControlDTO.getControlIdMap().values()).values());
        // 记录 移除控件选项缓存
        Set<Long> controlIdSet = StreamUtil.concatMapKeyValues(copyControlDTO.getControlIdMap());
        List<Long> controlIds = StreamUtil.filter(controlIdSet, ApplicationUtil::meaningfulId);
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.controlOption(controlIds).values());
        // 记录 移除选项缓存
        Set<Long> optionIdSet = new HashSet<>();
        copyControlDTO.getControlOptionIdMap().values().forEach(map -> optionIdSet.addAll(StreamUtil.concatMapKeyValues(map)));
        List<Long> optionIds = StreamUtil.filter(optionIdSet, ApplicationUtil::meaningfulId);
        cacheUtil.addClearRequestCache(ApplicationRedisKeyUtil.controlOption(optionIds).values());

        return copyControlDTO;
    }

    /**
     * 更新 控件 源控件id信息
     *
     * @param controlIdMap       版本控件id映射整合
     * @param controlSourceIdMap 版本源控件id映射整合
     */
    @Override
    public void modifyControlSourceId(Map<Long, Long> controlIdMap, Map<Long, Long> controlSourceIdMap) {
        // 更新 复制后 新控件 源控件id信息
        List<ApplicationFormControl> needChangeSourceIdControls = new ArrayList<>();
        Map<Long, Long> reversalControlIdMap = new HashMap<>();
        controlIdMap.forEach((key, value) -> reversalControlIdMap.put(value, key));
        this.findByControlIds(controlIdMap.values(), true).forEach(c -> {
            // 复制前 控件id
            Long oldControlId = reversalControlIdMap.get(c.getControlId());
            if (controlSourceIdMap.containsKey(oldControlId)) {
                // 复制前 源控件id
                Long oldSourceControlId = controlSourceIdMap.get(oldControlId);
                if (controlIdMap.containsKey(oldSourceControlId)) {
                    // 复制前 源控件id 对应的复制后 控件id
                    Long newControlId = controlIdMap.get(oldSourceControlId);
                    c.setSourceControlId(newControlId);
                    needChangeSourceIdControls.add(c);
                }
            }
        });
        logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, needChangeSourceIdControls);
    }

    /**
     * 删除表单控件
     *
     * @param form form
     */
    @Override
    public void deleteFormControl(ApplicationForm form) {
        List<ApplicationFormControl> controls = this.findByForm(form, false).stream()
                .peek(e -> e.setIsDeleted(SwitchEnum.YES.getId()))
                .collect(Collectors.toList());

        logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, controls);
    }

    /**
     * 递归保存控件
     *
     * @param parentControlId 上级控件id
     * @param controls        控件列表
     * @param saveControl     saveControl
     */
    private void recursionModifyControls(Long parentControlId, List<ControlDTO> controls, SaveControlRespDTO saveControl) {
        if (CollectionUtil.isEmpty(controls)) {
            return;
        }

        for (int i = 0; i < controls.size(); i++) {
            ControlDTO controlDTO = controls.get(i);
            ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(controlDTO.getControlCode());

            Long controlId;
            ApplicationFormControl control;
            // 如果前端传回来的控件id在数据库中
            if (saveControl.getDbControlMap().containsKey(controlDTO.getControlId())) {
                control = saveControl.getDbControlMap().get(controlDTO.getControlId());
                controlId = control.getControlId();
            } else {
                // 不允许出现控件ID为负数的，为负数的是特殊控件，特殊控件不需要储存
                if (Long.valueOf("0").compareTo(controlDTO.getControlId()) <= 0) {
                    throw new BusinessException(RCodeEnum.APPLICATION_FORM_CONTROL_NOT_EXIST);
                }
                controlId = null;
                control = new ApplicationFormControl();
                control.setEnterpriseId(saveControl.getForm().getEnterpriseId());
            }

            // 处理控件选择范围
            List<AppPermissionDTO> permissions = this.saveControlSelScore(control, controlDTO);

            BeanUtil.copyProperties(JSON.toJSON(controlDTO), control);
            control.setControlId(controlId);
            control.setFormId(saveControl.getForm().getFormId());
            control.setParentControlId(ObjectUtil.defaultIfNull(parentControlId, ApplicationUtil.DEFAULT_PARENT_CONTROL_ID));
            control.setSort(i);

            switch (DefaultValueTypeEnum.isExistById(control.getDefaultValueType()).orElse(DefaultValueTypeEnum.DIY)) {
                // 关联应用数据 需要清空 通过公式运算默认值
                case RELATED_FORM, RELATED_TABLE -> control.setFormula(null);
                // 通过公式运算 需要清空 关联公式
                case FORMULA_CALCULATION -> control.setRelatedFormula(null);
            }

            logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, control);

            // 覆盖为数据ID
            controlId = control.getControlId();
            controlDTO.setControlId(controlId);
            // 记录控件 新旧映射id
            saveControl.putControl(controlDTO, control);

            ModifyControl modifyControl = new ModifyControl(control, controlDTO, controlCodeEnum);

            // 处理下拉控件
            this.saveSelControl(modifyControl, saveControl.getDbControlOptionsMap(), saveControl);

            // 控件权限：（人员、部门）可选范围
            if (CollectionUtil.isNotEmpty(permissions)) {
                // 部门选择/人员选择
                ModifyAppPermissionReqDTO pendingDiverts = new ModifyAppPermissionReqDTO();
                pendingDiverts.setEnterpriseId(saveControl.getForm().getEnterpriseId());
                if (controlDTO instanceof DeptSelControlDTO) {
                    // 部门选择范围
                    pendingDiverts.setSourceType(ApplicationSourceTypeEnum.FORM_CONTROL_DEPT_SELECT_SCOPE.getId());
                } else {
                    // 人员选择范围
                    pendingDiverts.setSourceType(ApplicationSourceTypeEnum.FORM_CONTROL_MEMBER_SELECT_SCOPE.getId());
                }
                pendingDiverts.setSourceId(controlId);
                pendingDiverts.setPermissions(permissions);
                applicationPermissionService.modifyPermission(pendingDiverts);
            }

            // 保存控件关联配置
            this.saveControlRelateConfig(control, controlDTO);

            // 递归保存控件
            this.recursionModifyControls(controlId, controlDTO.getChildControls(), saveControl);

            // 处理标签页控件（必须等当前层递归结束后 处理）
            if (controlDTO instanceof TabsControlDTO) {
                this.handleTabsControl(control, ((TabsControlDTO) controlDTO).getTabsConfig(), saveControl.getControlMap());
            }
            // 处理表格控件（必须等当前层递归结束后 处理）
            else if (controlDTO instanceof TableControlDTO) {
                this.handleTableControl(control, saveControl);
            }
        }
    }

    /**
     * 递归复制表单控件
     *
     * @param targetSourceControlMap       目标控件与源映射map
     * @param sourceControlOptionMap       源控件选项map
     * @param targetSourceControlOptionMap 目标控件选项与源映射map
     * @param parentControlId              上级控件id
     * @param sourceControlTree            源控件树
     * @param copyControlDTO               复制控件 返回实体
     * @param updateSource                 是否更新源映射
     */
    private void recursionCopyControl(Map<Long, ApplicationFormControl> targetSourceControlMap,
                                      Map<Long, List<FormControlOptionBO>> sourceControlOptionMap,
                                      Map<Long, Map<Long, FormControlOption>> targetSourceControlOptionMap,
                                      Long parentControlId,
                                      List<FormControlBO> sourceControlTree,
                                      CopyControlDTO copyControlDTO,
                                      boolean updateSource) {
        if (CollectionUtil.isEmpty(sourceControlTree)) {
            return;
        }
        sourceControlTree.forEach(controlBO -> {
            ApplicationFormControl copyControl;
            Long controlId;
            if (targetSourceControlMap.containsKey(controlBO.getControlId())) {
                copyControl = targetSourceControlMap.get(controlBO.getControlId());
                controlId = copyControl.getControlId();
            } else {
                controlId = null;
                copyControl = new ApplicationFormControl();
            }
            BeanUtil.copyProperties(controlBO, copyControl, SpecialFieldEnum.getSpecialFields());
            copyControl.setControlId(controlId);
            copyControl.setFormId(copyControlDTO.getForm().getFormId());
            copyControl.setParentControlId(ObjectUtil.defaultIfNull(parentControlId, ApplicationUtil.DEFAULT_PARENT_CONTROL_ID));
            copyControl.setSourceControlId(controlBO.getControlId());

            logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, copyControl);
            controlId = copyControl.getControlId();
            // 记录控件
            copyControlDTO.putControl(controlBO, copyControl);

            // 更新源映射信息
            if (updateSource && !controlBO.getSourceControlId().equals(controlId)) {
                controlBO.setSourceControlId(controlId);
                ApplicationFormControl control = BeanUtil.copyProperties(controlBO, ApplicationFormControl.class);
                logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, control);
            }

            ControlCodeEnum controlCodeEnum = ControlCodeEnum.findByCode(copyControl.getControlCode());

            // 选择控件
            this.copySelControl(sourceControlOptionMap, targetSourceControlOptionMap, copyControl, controlBO, copyControlDTO, controlCodeEnum, updateSource);

            // 复制控件关联
            applicationFormControlRelatedService.copyControlRelated(controlBO, copyControl);

            // 复制条件判断
            Long sourceId = controlBO.getControlId();
            Long targetId = controlId;
            Long enterpriseId = copyControl.getEnterpriseId();
            applicationJudgeService.copyJudges(new CopyJudgeReqDTO(JudgeSourceTypeEnum.CONTROL_RELATED_FILTER_CONDITION, enterpriseId, sourceId, targetId));

            // 递归复制表单控件
            this.recursionCopyControl(
                    targetSourceControlMap,
                    sourceControlOptionMap,
                    targetSourceControlOptionMap,
                    controlId,
                    controlBO.getChild(),
                    copyControlDTO,
                    updateSource
            );

            // 处理标签页控件（必须等当前层递归结束后 处理）
            if (ControlCodeEnum.TABS == controlCodeEnum) {
                this.handleTabsControl(copyControl, JSON.parseArray(copyControl.getTabsConfig(), TabsConfigDTO.class), copyControlDTO.getControlMap());
            }
            // 处理表格控件（必须等当前层递归结束后 处理）
            else if (ControlCodeEnum.TABLE == controlCodeEnum) {
                this.handleTableControl(copyControl, copyControlDTO);
            }
        });
    }

    /**
     * 递归处理 控件条件
     *
     * @param conditions   conditions
     * @param controlBases controlBases
     */
    private void recursionControlCondition(List<ControlConditionRespDTO> conditions, List<ControlBaseInfoDTO> controlBases) {
        controlBases.forEach(c -> {
            if (ControlCodeEnum.TABS.getCode().equals(c.getControlCode())) {
                this.recursionControlCondition(conditions, c.getChildControls());
            } else {
                if (ControlCodeEnum.TABLE.getCode().equals(c.getControlCode())) {
                    // 有子级控件 （表格需要特殊处理）
                    c.getChildControls().forEach(child -> conditions.add(new ControlConditionRespDTO(c, child)));
                } else {
                    // 无子级控件
                    conditions.add(new ControlConditionRespDTO(c));
                }
            }
        });
    }

    /**
     * 保存选择控件
     *
     * @param modifyControl      modifyControl
     * @param controlsOptionsMap controlsOptionsMap
     * @param saveControl        saveControl
     */
    private void saveSelControl(ModifyControl modifyControl, Map<Long, Map<Long, FormControlOption>> controlsOptionsMap, SaveControlRespDTO saveControl) {
        ApplicationFormControl control = modifyControl.getControl();
        ControlDTO controlDTO = modifyControl.getControlDTO();
        ControlCodeEnum controlCodeEnum = modifyControl.getControlCodeEnum();
        if (!(controlDTO instanceof SelectControlDTO selectControlRespDTO)) {
            return;
        }
        Map<Long, FormControlOption> controlOptionMap = controlsOptionsMap.getOrDefault(control.getControlId(), new HashMap<>());
        // 递归保存控件选择项
        formControlOptionService.recursionSaveOptions(control.getControlId(), ApplicationConstant.DEFAULT_PARENT_OPTION_ID,
                controlOptionMap, selectControlRespDTO.getOptions(), saveControl);

        Map<Long, Long> controlOptionIdMap = saveControl.getOptionIdMapByControlId(control.getControlId());
        // 删除已无效的选择项
        List<FormControlOption> deletedOptions = controlOptionMap.entrySet().stream()
                .filter(entry -> !controlOptionIdMap.containsValue(entry.getKey()))
                .map(Map.Entry::getValue)
                .peek(e -> e.setIsDeleted(SwitchEnum.YES.getId()))
                .collect(Collectors.toList());

        logService.saveAndCheck(formControlOptionMapper, FormControlOption::getOptionId, deletedOptions);

        // 该控件有选项值
        if (StringUtils.isNotBlank(controlDTO.getDefaultValue())) {
            String errorMsg = String.format("[%s]控件[%s]默认值错误", controlCodeEnum.getName(), controlDTO.getControlTitle());
            // 选项控件默认值 把name变成id储存
            String defaultValue;
            try {
                if (controlCodeEnum.isMultiple()) {
                    // 多选
                    List<Long> longs = JSON.parseArray(controlDTO.getDefaultValue(), Long.class);
                    defaultValue = longs.stream().map(optionId -> {
                        if (!controlOptionIdMap.containsKey(optionId)) {
                            throw new BusinessException(BaseEnum.ERROR_PARAMETER, errorMsg);
                        }
                        return controlOptionIdMap.get(optionId);
                    }).toList().toString();
                } else {
                    // 单选
                    Long optionId = Long.valueOf(controlDTO.getDefaultValue());
                    if (!controlOptionIdMap.containsKey(optionId)) {
                        throw new BusinessException(BaseEnum.ERROR_PARAMETER, errorMsg);
                    }
                    defaultValue = controlOptionIdMap.get(optionId).toString();
                }
            } catch (NumberFormatException e) {
                throw new BusinessException(BaseEnum.ERROR_PARAMETER, errorMsg);
            }

            control.setDefaultValue(defaultValue);
            logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, control);
        }
    }

    /**
     * 复制选择控件
     *
     * @param sourceControlOptionMap       源控件选项map
     * @param targetSourceControlOptionMap 目标控件选项与源映射map
     * @param copyControl                  copyControl
     * @param controlBO                    controlBO
     * @param copyControlDTO               copyControlRespDTO
     * @param controlCodeEnum              controlCodeEnum
     * @param updateSource                 是否更新源映射
     */
    private void copySelControl(Map<Long, List<FormControlOptionBO>> sourceControlOptionMap,
                                Map<Long, Map<Long, FormControlOption>> targetSourceControlOptionMap,
                                ApplicationFormControl copyControl,
                                FormControlBO controlBO,
                                CopyControlDTO copyControlDTO,
                                ControlCodeEnum controlCodeEnum,
                                boolean updateSource) {
        if (!controlCodeEnum.hasOptions()) {
            return;
        }
        Long controlId = copyControl.getControlId();
        List<FormControlOptionBO> sourceOptions = sourceControlOptionMap.getOrDefault(controlBO.getControlId(), new ArrayList<>());
        Map<Long, FormControlOption> targetSourceOptionMap = targetSourceControlOptionMap.getOrDefault(controlId, new HashMap<>());

        // 递归复制表单控件选项
        formControlOptionService.recursionCopyOptions(controlId, ApplicationConstant.DEFAULT_PARENT_OPTION_ID,
                sourceOptions, targetSourceOptionMap, copyControlDTO, updateSource);

        Map<Long, Long> optionIdMap = copyControlDTO.getOptionIdMapByControlId(controlId);
        // 更新默认选择
        if (StringUtils.isNotBlank(copyControl.getDefaultValue())) {
            String defaultValue = null;
            if (controlCodeEnum.isMultiple()) {
                defaultValue = JSON.parseArray(copyControl.getDefaultValue(), Long.class).stream()
                        .filter(optionIdMap::containsKey)
                        .map(optionIdMap::get)
                        .toList().toString();
            } else {
                Long optionId = Long.valueOf(copyControl.getDefaultValue());
                if (optionIdMap.containsKey(optionId)) {
                    defaultValue = Long.toString(optionIdMap.get(optionId));
                }
            }
            copyControl.setDefaultValue(defaultValue);
            logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, copyControl);
        }

        // 删除失效表单控件选项
        List<Long> sourceOptionIds = sourceOptions.stream().map(FormControlOption::getSourceOptionId).toList();
        List<FormControlOption> deletedOptions = targetSourceOptionMap.values().stream()
                .filter(e -> !sourceOptionIds.contains(e.getOptionId()))
                .peek(e -> e.setIsDeleted(SwitchEnum.YES.getId()))
                .collect(Collectors.toList());
        logService.saveAndCheck(formControlOptionMapper, FormControlOption::getOptionId, deletedOptions);
    }

    /**
     * 处理表格控件
     *
     * @param control     control
     * @param saveControl saveControl
     */
    private void handleTableControl(ApplicationFormControl control, SaveControlDTO saveControl) {
        if (StringUtils.isBlank(control.getDefaultValue())) {
            return;
        }

        String defaultValue = control.getDefaultValue();
        List<Map<String, Object>> tableDefaultRow = JSON.parseArray(defaultValue).stream().map(o -> {
            Map<String, Object> map = new LinkedHashMap<>();
            ((JSONObject) o).forEach((controlField, value) -> {
                map.put(controlField, value);
                ApplicationFormControl formControl = saveControl.getControlByField(controlField);
                // 选项值处理
                ControlCodeEnum codeEnum = ControlCodeEnum.findByCode(formControl.getControlCode());
                if (!codeEnum.hasOptions() || org.springframework.util.ObjectUtils.isEmpty(value)) {
                    return;
                }
                if (codeEnum.isMultiple()) {
                    // 多值
                    List<Long> optionIds;
                    try {
                        optionIds = JSON.parseArray(value.toString(), Long.class);
                    } catch (Exception e) {
                        throw new BusinessException(BaseEnum.ERROR_PARAMETER, "表格默认数据选项值错误");
                    }
                    value = StreamUtil.transListT(optionIds, e -> saveControl.getNewOptionId(formControl.getControlId(), e));
                } else {
                    // 单值
                    long oldOptionId;
                    try {
                        oldOptionId = Long.parseLong(value.toString());
                    } catch (NumberFormatException e) {
                        throw new BusinessException(BaseEnum.ERROR_PARAMETER, "表格默认数据选项值错误");
                    }
                    value = saveControl.getNewOptionId(formControl.getControlId(), oldOptionId);
                }
                map.replace(controlField, value);
            });
            return map;
        }).collect(Collectors.toList());

        // 重新更新
        control.setDefaultValue(JSON.toJSONString(tableDefaultRow));
        logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, control);
    }

    /**
     * 处理标签页控件
     *
     * @param control    control
     * @param tabsConfig tabsConfig
     * @param controlMap controlMap
     */
    private void handleTabsControl(ApplicationFormControl control, List<TabsConfigDTO> tabsConfig, Map<Long, ApplicationFormControl> controlMap) {
        // 标签页控件 默认数据中记录每一个标签页有哪些控件，前端回传的控件id 需要替换成实际入库的控件id
        tabsConfig.forEach(tab -> tab.setChildrenIds(tab.getChildrenIds().stream().map(tabControlId -> {
            if (!controlMap.containsKey(tabControlId)) {
                throw new BusinessException(BaseEnum.ERROR_PARAMETER, "标签页子控件id不存在");
            }
            return controlMap.get(tabControlId).getControlId();
        }).toList()));

        // 重新更新
        control.setTabsConfig(JSON.toJSONString(tabsConfig));
        logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, control);
    }

    /**
     * 保存控件关联配置
     *
     * @param controlDTO controlDTO
     */
    private void saveControlRelateConfig(ApplicationFormControl control, ControlDTO controlDTO) {
        ControlRelatedConfigDTO controlRelatedConfig = controlDTO.getControlRelatedConfig();
        if (Objects.isNull(controlRelatedConfig)) {
            return;
        }
        List<ControlRelatedDTO> controlRelatedBases = controlRelatedConfig.getControlRelatedBases();
        List<JudgeOr> judgeOrs = controlRelatedConfig.getJudgeOrs();
        if (CollectionUtil.isEmpty(controlRelatedBases)) {
            return;
        }

        // 获取目标应用表单控件code
        Map<Long, String> controlCodeMap = this.controlCodeMap(controlDTO.getRelatedFormId(), true);

        // 新增的控件，前端传上来这里是临时ID
        controlRelatedBases.forEach(e -> {
            e.setFormId(control.getFormId());
            e.setControlId(control.getControlId());
            e.setRelatedFormId(control.getRelatedFormId());
        });
        applicationFormControlRelatedService.saveControlRelated(control, controlRelatedBases);

        // 筛选条件
        if (!CollectionUtil.isEmpty(judgeOrs)) {
            // 检查 条件判断
            applicationJudgeService.checkJudge(judgeOrs, controlCodeMap, null);
            // 保存条件
            applicationJudgeService.saveJudges(new JudgesDTO(JudgeSourceTypeEnum.CONTROL_RELATED_FILTER_CONDITION, control.getEnterpriseId(), controlDTO.getControlId(), judgeOrs));
        }
    }

    /**
     * 处理控件选择范围
     *
     * @param controlDTO controlDTO
     * @return AppPermissionDTO 列表
     */
    private List<AppPermissionDTO> saveControlSelScore(ApplicationFormControl control, ControlDTO controlDTO) {
        ControlSelectConfigDTO config = null;
        Map<Integer, List<Long>> dynamicTypeTargetsMap = new HashMap<>();
        // 命令
        ControlSelScopeCommand controlSelScopeCommand = new ControlSelScopeCommand();
        if (controlDTO instanceof MemberSelControlDTO memberSelControlDTO) {
            // 人员选择控件 指定范围值另存权限表
            config = memberSelControlDTO.getControlSelectConfig();

            // 命令-部门
            controlSelScopeCommand.putDefault(ApplicationPermissionTypeEnum.DEPARTMENT, dynamicTypeTargetsMap);
            // 命令-动态部门
            controlSelScopeCommand.put(ApplicationPermissionTypeEnum.DYNAMIC_DEPARTMENT, (map, entry) -> {
                List<DepartmentBaseRespDTO> departmentBases = remoteUserDepartmentService.loginUserDepartmentBases();
                return StreamUtil.transListTF(departmentBases, DepartmentBaseRespDTO::getDepartmentId, e -> !entry.getValue().contains(e));
            });

        } else if (controlDTO instanceof DeptSelControlDTO deptSelControlDTO) {
            config = deptSelControlDTO.getControlSelectConfig();

            // 命令-角色、部门、人员
            controlSelScopeCommand.putDefault(ApplicationPermissionTypeEnum.USER, dynamicTypeTargetsMap);
            controlSelScopeCommand.putDefault(ApplicationPermissionTypeEnum.DEPARTMENT, dynamicTypeTargetsMap);
            controlSelScopeCommand.putDefault(ApplicationPermissionTypeEnum.ROLE, dynamicTypeTargetsMap);
            controlSelScopeCommand.put(ApplicationPermissionTypeEnum.ROLE, (map, entry) -> {
                // 当前登录人
                if (!entry.getValue().contains(loginUtil.getLoginUserId())) {
                    return ListUtil.toList(loginUtil.getLoginUserId());
                }
                return new ArrayList<>();
            });
        }

        List<AppPermissionDTO> scope = new ArrayList<>();
        if (!Objects.isNull(config)) {
            scope.addAll(config.getScope());
            Map<Integer, List<Long>> scopeTypeTargetsMap = StreamUtil.groupAndThenTrans(scope, AppPermissionDTO::getPermissionType, AppPermissionDTO::getTargetId);
            dynamicTypeTargetsMap.putAll(StreamUtil.groupAndThenTrans(config.getDynamic(), AppPermissionDTO::getPermissionType, AppPermissionDTO::getTargetId));

            scopeTypeTargetsMap.entrySet().forEach(entry -> {
                if (dynamicTypeTargetsMap.containsKey(entry.getKey())) {
                    scope.addAll(StreamUtil.transListT(controlSelScopeCommand.actionKey(dynamicTypeTargetsMap, entry), e -> new AppPermissionDTO(entry.getKey(), e)));
                }
            });

            // 置空入库
            config.setBlank();
            control.setControlSelectConfig(JSON.toJSONString(config));
        }
        return scope;
    }

    /**
     * 保存部门/成员选择控件选择范围
     *
     * @param target       目标表单
     * @param controls     控件列表
     * @param controlIdMap 新旧表单控件id映射
     * @param isMember     人员/部门，true：成员
     */
    private void copyControlSelScore(ApplicationForm target, List<ApplicationFormControl> controls, Map<Long, Long> controlIdMap, boolean isMember) {
        ControlCodeEnum controlCodeEnum = isMember ? ControlCodeEnum.MEMBER_SEL : ControlCodeEnum.DEPT_SEL;
        int applicationSourceType;
        if (isMember) {
            applicationSourceType = ApplicationSourceTypeEnum.FORM_CONTROL_MEMBER_SELECT_SCOPE.getId();
        } else {
            applicationSourceType = ApplicationSourceTypeEnum.FORM_CONTROL_DEPT_SELECT_SCOPE.getId();
        }

        AppPermissionsReqDTO appPermissionsReqDTO = new AppPermissionsReqDTO();
        appPermissionsReqDTO.setSourceType(applicationSourceType);
        List<Long> controlIds = StreamUtil.transListFT(controls, e -> controlCodeEnum.equalsCode(e.getControlCode()), ApplicationFormControl::getControlId);
        appPermissionsReqDTO.setSourceIds(controlIds);

        // 遍历 新旧表单控件id映射 保存
        ModifyAppPermissionReqDTO modifyAppPermissionReqDTO = new ModifyAppPermissionReqDTO();
        modifyAppPermissionReqDTO.setEnterpriseId(target.getEnterpriseId());
        modifyAppPermissionReqDTO.setSourceType(applicationSourceType);
        applicationPermissionService.findDTOByAppPermissions(appPermissionsReqDTO).forEach((sourceId, permissions) -> {
            if (controlIdMap.containsKey(sourceId)) {
                modifyAppPermissionReqDTO.setSourceId(controlIdMap.get(sourceId));
                modifyAppPermissionReqDTO.setPermissions(permissions);
                applicationPermissionService.modifyPermission(modifyAppPermissionReqDTO);
            }
        });
    }

    /**
     * 校验表单控件
     *
     * @param controls controls
     */
    private void checkFormControl(List<ControlDTO> controls) {
        if (CollectionUtil.isEmpty(controls)) {
            return;
        }
        for (ControlDTO control : controls) {
            ControlRelatedConfigDTO controlRelatedConfig = control.getControlRelatedConfig();
            if (control instanceof OrderSelectControlDTO) {
                if (null == controlRelatedConfig || CollectionUtil.isEmpty(controlRelatedConfig.getControlRelatedBases())) {
                    String errorMsg = String.format("控件[%s]请选择关联设置", control.getControlTitle());
                    throw new BusinessException(BaseEnum.ERROR_PARAMETER, errorMsg);
                }
            }
            // 人员选择
            else if (control instanceof MemberSelControlDTO memberSelControlDTO) {
                ControlSelectConfigDTO controlSelectConfigDTO = memberSelControlDTO.getControlSelectConfig();
                // 指定
                if (PermissionStatusEnum.ASSIGN.getId() == controlSelectConfigDTO.getPermissionStatus()
                        && CollectionUtil.isNotEmpty(controlSelectConfigDTO.getScope())) {
                    if (!applicationPermissionService.checkPermission(controlSelectConfigDTO.getScope())) {
                        String errorMsg = String.format("控件[%s]范围选择参数错误", control.getControlTitle());
                        throw new BusinessException(BaseEnum.ERROR_PARAMETER, errorMsg);
                    }
                }
            }
            // 引用
            else if (control instanceof QuoteControlDTO quoteControlDTO) {
                if (null == controlRelatedConfig || CollectionUtil.isEmpty(controlRelatedConfig.getControlRelatedBases())) {
                    String errorMsg = String.format("控件[%s]请选择关联设置", control.getControlTitle());
                    throw new BusinessException(BaseEnum.ERROR_PARAMETER, errorMsg);
                }
                List<ControlRelatedDTO> controlRelatedBases = controlRelatedConfig.getControlRelatedBases();
                boolean b = controlRelatedBases.stream().anyMatch(e -> {
                    ControlBaseDTO relatedControl = this.baseMapper.findBaseById(e.getRelatedControlId());
                    return ControlCodeEnum.isQuote(relatedControl.getControlCode());
                });
                if (b) {
                    String errorMsg = String.format("控件[%s]不可以重复引用", control.getControlTitle());
                    throw new BusinessException(BaseEnum.ERROR_PARAMETER, errorMsg);
                }
            }
            // 子级
            this.checkFormControl(control.getChildControls());
        }
    }

    /**
     * 删除表单控件
     *
     * @param deletedControls deletedControls
     */
    private void deleteFormControls(List<ApplicationFormControl> deletedControls) {
        deletedControls.forEach(c -> c.setIsDeleted(SwitchEnum.YES.getId()));
        logService.saveAndCheck(this.baseMapper, ApplicationFormControl::getControlId, deletedControls);

        List<Long> controlIds = StreamUtil.transListT(deletedControls, ApplicationFormControl::getControlId);
        List<FormControlOption> options = formControlOptionMapper.findByControlIds(controlIds, true);
        options.forEach(o -> o.setIsDeleted(SwitchEnum.YES.getId()));
        logService.saveAndCheck(formControlOptionMapper, FormControlOption::getOptionId, options);
    }

    @AllArgsConstructor
    @Getter
    private static class ModifyControl {
        private final ApplicationFormControl control;
        private final ControlDTO controlDTO;
        private final ControlCodeEnum controlCodeEnum;
    }
}
